/*
This file is part of MMM.

MMM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

MMM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with MMM.  If not, see <http://www.gnu.org/licenses/>.
*
* @package    MMMTools
* @copyright  2015 High Performance Humanoid Technologies (H2T), Karlsruhe, Germany
*
*/

#include "../common/ConverterApplicationHelper.h"
#include "MMMConverterConfiguration.h"

bool convertMMMData(const MMMConverterConfiguration& c)
{
    // Load source model
    MMM::ModelPtr sourceModel;
    if (!c.sourceModelFile.empty())
    {
        sourceModel = readModel(c.sourceModelFile);
        if (!sourceModel)
            return false;

        if (!c.sourceModelProcessor.empty() && !c.sourceModelProcessorConfigFile.empty())
        {
            MMM::ModelProcessorPtr sourceModelProcessor = setupModelProcessor(c.sourceModelProcessor, c.sourceModelProcessorConfigFile);
            if (!sourceModelProcessor)
                return false;

            sourceModel = sourceModelProcessor->convertModel(sourceModel);
        }
    }

    // Load target model
    MMM::ModelPtr targetModel, targetModelProcessed;
    MMM::ModelProcessorPtr targetModelProcessor;

    targetModel = readModel(c.targetModelFile);
    if (!targetModel)
        return false;

    if (!c.targetModelProcessor.empty() && !c.targetModelProcessorConfigFile.empty())
    {
        targetModelProcessor = setupModelProcessor(c.targetModelProcessor, c.targetModelProcessorConfigFile);
        if (!targetModelProcessor)
            return false;

        targetModelProcessed = targetModelProcessor->convertModel(targetModel);
    } else
        targetModelProcessed = targetModel;

    MMM::AbstractMotionPtr inputMotion;
    if (c.inputFileType == ConverterApplicationBaseConfiguration::C3D)
        inputMotion = readMarkerMotion(c.inputFile, c.markerPrefix);
    else if (c.inputFileType == ConverterApplicationBaseConfiguration::MMM)
        inputMotion = readMMMMotion(c.inputFile);

    if (!inputMotion)
    {
        MMM_ERROR << "Could not read input file or unknown input file type!" << std::endl;
        return false;
    }

    // Create converter
    MMM::ConverterPtr converter = createConverter(c.converterName, c.converterConfigFile);
    if (!converter)
        return false;

    // TODO: do this somewhere else?
    if (sourceModel)
        converter->setSourceModelSize(sourceModel->getHeight());

    converter->setup(sourceModel, inputMotion, targetModelProcessed);

    // Convert motion
    MMM::AbstractMotionPtr outputMotion = converter->convertMotion();
    if (!outputMotion)
    {
        MMM_ERROR << "Could not convert motion with converter!" << std::endl;
        return false;
    }

    // Setup motion and serialize motion to XML string
    std::string motionXML;

    MMM::LegacyMotionPtr outputMotionCasted = boost::dynamic_pointer_cast<MMM::LegacyMotion>(outputMotion);
	if (outputMotionCasted)
	{
        outputMotionCasted->setModel(targetModelProcessed, targetModel);

        if (targetModelProcessor)
            outputMotionCasted->setModelProcessor(targetModelProcessor);

        if (!c.outputMotionName.empty())
            outputMotionCasted->setName(c.outputMotionName);

        outputMotionCasted->setMotionFilePath(MMM::XML::getPath(c.outputFile));

		motionXML = outputMotionCasted->toXML();
	}
	else
        motionXML = outputMotion->toXML();  // Should not happen for converters included with MMMTools

    // Write XML to output file
    return MMM::XML::saveXML(c.outputFile, motionXML);
}

int main(int argc, char *argv[])
{
    MMM_INFO << "--- MMM CONVERTER ---" << std::endl;

    MMMConverterConfiguration c;
    if (!c.processCommandLine(argc,argv))
    {
        MMM_ERROR << "Could not process command line, aborting." << std::endl;
        return -1;
    }

    c.print();

    bool res = convertMMMData(c);

    if (res)
        MMM_INFO << "Successfully converted motion." << std::endl;
    else
    {
        MMM_INFO << "Failed to convert motion!" << std::endl;
        return -2;
    }

    MMM_INFO << "--- END ---" << std::endl;

	return 0;
}
